import got, { Method } from 'got'
import { Injectable } from '@nestjs/common'
import { AzureAppOAuthService } from './azure-app-oauth.service'
import { getRandomInt } from 'src/utils'
import { RepositoryService } from './repository.service'
import { AzureApp } from 'src/typings'

const caches: {
  [key: string]: {
    running: boolean
    statistics: {
      [key: string]: {
        ok: number
        error: number
      }
    }
    startTime: Date
  }
} = {}

@Injectable()
export class AzureAppRenewService {

  private apis: ApiDefine[]
  private readonly repo: RepositoryService<AzureApp>

  constructor(
    private readonly azureAppOAuthService: AzureAppOAuthService,
  ) {
    this.repo = new RepositoryService('azure-app.json', 'clientId')

    this.apis = [
      { name: '用户-用户-列出用户', url: 'users' },
      { name: '用户-见解-Office Graph见解-共享的列表', url: 'me/insights/shared' },
      { name: '用户-见解-Office Graph见解-列出趋势', url: 'me/insights/trending' },
      { name: '用户-见解-Office Graph见解-使用的列表', url: 'me/insights/used' },
      { name: '用户-组织层次结构-列出直接下属', url: 'me/directReports' },
      // 预览版的首选
      { name: '用户-用户设置-获取设置', url: 'me/settings' },
      { name: '用户-组-列出加入的团队', url: 'me/joinedTeams' },
      { name: '用户-组-列出隶属于', url: 'me/memberOf' },
      { name: '用户-待办任务-创建任务列表', url: 'me/todo/lists' },
      { name: '日历-日历-列出日历', url: 'me/calendars' },
      { name: '日历-日历组-列出日历组', url: 'me/calendarGroups' },
      { name: '云通信-状态-获取状态', url: 'me/presence' },
      // 客户预定
      { name: '文件-驱动器-列出驱动器', url: 'me/drives' },
      { name: '文件-驱动器-列出子项', url: 'me/drive/root/children' },
      { name: '文件-驱动器-最近使用的文件', url: 'me/drive/recent' },
      { name: '文件-驱动器-列出关注的项', url: 'me/drive/following' },
      // todo 上传文件 https://docs.microsoft.com/zh-cn/graph/api/driveitem-put-content?view=graph-rest-1.0&tabs=http
      { name: '邮件-列出邮件', url: 'me/messages' },
      // 发送邮件
      { name: '邮件-邮件文件夹-列出邮件文件夹', url: 'me/mailFolders' },
      { name: '邮件-规则-列出规则', url: 'me/mailFolders/inbox/messageRules' },
      { name: '邮件-类别-列出类别', url: 'me/outlook/masterCategories' },
      { name: '注释-笔记本-列出笔记本', url: 'me/onenote/notebooks' },
      { name: '注释-部分-列出分区', url: 'me/onenote/sections' },
      { name: '注释-分区组-列出分区组', url: 'me/onenote/sectionGroups' },
      { name: '注释-页面-列出页面', url: 'me/onenote/pages' },
      { name: '人员和工作场所智能-人员-列出人员', url: 'me/people' },
      { name: '人员和工作场所智能-见解-趋势-列出趋势', url: 'me/insights/trending' },
      { name: '人员和工作场所智能-见解-使用的内容-使用的列表', url: 'me/insights/used' },
      { name: '人员和工作场所智能-见解-共享的内容-共享的列表', url: 'me/insights/shared' },
      { name: '个人联系人-联系人-列出联系人', url: 'me/contacts' },
      { name: '个人联系人-联系人文件夹-列出联系人文件夹', url: 'me/contactFolders' },
      { name: '个人联系人-类别-列出类别', url: 'me/outlook/masterCategories' },
      { name: '网站和列表-网站-关注网站列表', url: 'me/followedSites' },
      { name: '任务和计划-任务-获取用户的任务', url: 'me/planner/tasks' },
    ]
  }

  private init(clientId: string) {
    if (!caches[clientId]) {
      caches[clientId] = {
        running: false,
        statistics: this.apis.reduce((previousValue, currentValue, currentIndex, array) => {
          previousValue[array[currentIndex].name] = { ok: 0, error: 0 }
          return previousValue
        }, {}),
        startTime: new Date()
      }
    }
  }

  public async start(clientId: string) {
    this.repo.findOneOrFail(n => n.clientId === clientId)
    this.init(clientId)
    if (caches[clientId].running) {
      return
    }
    caches[clientId].running = true

    let action = () => {
      setTimeout(() => {
        if (!caches[clientId] || !caches[clientId].running) {
          return
        }
        let token = this.azureAppOAuthService.getTokenFromCache(clientId)
        if (token) {
          let { name, url, method = 'GET' } = this.apis[getRandomInt(0, this.apis.length)]
          got(url, {
            method: method,
            prefixUrl: 'https://graph.microsoft.com/v1.0/',
            timeout: 30 * 1000,
            headers: {
              Authorization: token.access_token
            }
          }).then(res => {
            caches[clientId].statistics[name].ok++
            console.log('renew api ok', name)
          }, (res) => {
            caches[clientId].statistics[name].error++
            console.log('renew api error', name)
            console.log(res)
          }).finally(() => {
            action()
          })
        } else {
          caches[clientId].running = false
        }
      }, getRandomInt(1000, 60 * 1000))
    }
    action()
  }

  public stop(clientId: string) {
    if (caches[clientId]) {
      caches[clientId].running = false
    }
  }

  public getRenewInfo(clientId: string) {
    return caches[clientId]
  }

}

interface ApiDefine {
  name: string
  method?: Method
  url: string
}